package com.fyf.game.net.server;

import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import org.je.log.JLog;
import com.fyf.game.net.NioUtil;
import com.fyf.game.net.ReceiveHandler;

/**
 * @author fanyifeng 2013-1-8 下午2:06:12
 */
public class MessageServer extends Thread
{
	private Selector	sel;
	private int			port;
	private boolean		closed;

	private int			transporterCount;
	private int			loopIndex;

	private RunEnvir	env;

	/**
	 * @param port
	 * @param handler
	 */
	public MessageServer(int port, ReceiveHandler handler) {
		this.port = port;
		this.closed = false;
		this.loopIndex = 0;
		this.sel = NioUtil.createSelector();
		ServerSocketChannel ssc = NioUtil.createAsynServerChannel(this.port);
		try {
			ssc.register(sel, SelectionKey.OP_ACCEPT);
		} catch (ClosedChannelException ex) {
			throw new RuntimeException(ex);
		}
		env = new RunEnvir();
		transporterCount = Runtime.getRuntime().availableProcessors();
		env.initTransporters(transporterCount, handler);
		env.serverPort = port;// 监控信息
	}

	public RunEnvir getRunEnvir() {
		return env;
	}

	public void run() {
		for (Transporter trans : env.tsps) {
			trans.start();
		}
		env.isServerStart = true;// 监控
		while (!closed) {
			if (doSelect() <= 0) {
				continue;
			}
			Iterator<SelectionKey> it = sel.selectedKeys().iterator();
			while (it.hasNext()) {
				SelectionKey key = it.next();
				it.remove();
				if (key.isValid() && key.isAcceptable()) {
					doAccept(key);
				}
			}
		}
		env.isServerStart = false;// 监控
		try {
			sel.close();
		} catch (Exception ex) {
			JLog.error(ex);
		}
		env.closeCount.incrementAndGet();// 退出计数
	}

	public void doAccept(SelectionKey key) {
		ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
		SocketChannel channel = null;
		try {
			channel = ssc.accept();
		} catch (IOException ex) {
			JLog.error(ex);
		}
		if (channel == null) {
			env.errorAcceptCount.incrementAndGet();
			return;
		}
		try {
			channel.configureBlocking(false);
			env.tsps[loopIndex].addChannel(channel);
			++loopIndex;
			if (loopIndex >= transporterCount) {
				loopIndex = 0;
			}
			env.successAcceptCount.incrementAndGet();
		} catch (Exception ex) {
			env.errorAcceptCount.incrementAndGet();
			try {
				channel.close();
			} catch (Exception e) {}
			JLog.error(ex);
		}
	}

	public void close() {
		closed = true;
		sel.wakeup();
		for (Transporter trans : env.tsps) {
			trans.close();
		}
	}

	private int doSelect() {
		try {
			return sel.select();
		} catch (Exception ex) {
			JLog.error(ex);
			return -1;
		}
	}
}
